home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / BlobMgr / Demo Folder / Ttt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  6.8 KB  |  369 lines  |  [TEXT/KAHL]

  1. /*
  2.  * Blob Manager Demonstration:  Tic-Tac-Toe
  3.  * 
  4.  * 25 July 1986    Paul DuBois
  5.  *
  6.  * 28 Dec 93
  7.  * - Convert from picture blobs to procedure blobs
  8.  */
  9.  
  10. # include    "TransSkel.h"
  11.  
  12. # include    "BlobMgr.h"
  13. # include    "BlobDemo.h"
  14.  
  15.  
  16. # define    barWidth    3    /* board line size */
  17. # define    bSqSize        30    /* board square size */
  18. # define    pSqSize        28    /* playing piece square size */
  19. # define    yOffMesg    4
  20. # define    yOffPiece    24    /* offset of top of pieces */
  21. # define    xOffBoard    25
  22. # define    yOffBoard    59
  23. # define    xMid        73    /* xOffBoard + 1.5(bSqSize) + barWidth */
  24. # define    yOffBut        165
  25.  
  26.  
  27. static WindowPtr        wind;
  28. static BlobSetHandle    tttReceptors;    /* receptor blobs (board) */
  29. static BlobSetHandle    tttDonors;        /* donor blobs (pieces) */
  30. static BlobHandle        xBlob;            /* handles to each piece */
  31. static BlobHandle        oBlob;
  32.  
  33. static Boolean            haveWin;
  34. static Boolean            wait = false;
  35. static ControlHandle    restartCtl;
  36. static short            moves;
  37. static short            firstPlayer = 0;
  38. static Str255            statusStr;
  39.     
  40.  
  41. static void
  42. StatusMesg (StringPtr s)
  43. {
  44. Rect    r;
  45.  
  46.     SetRect (&r, xMid-40, yOffMesg, xMid+40, yOffMesg+20);
  47.     TextBox    (s+1, (long) s[0], &r, teJustCenter);
  48.     StrCpy (statusStr, s);
  49. }
  50.  
  51.  
  52. static void
  53. GameOver (StringPtr mesg)
  54. {
  55.     HiliteControl (restartCtl, normalHilite);
  56.     StatusMesg (mesg);
  57.     wait = true;
  58. }
  59.  
  60.  
  61.  
  62. static void
  63. SelectPlayer (void)
  64. {
  65. BlobHandle    b;
  66. short        i;
  67.  
  68.     i = (moves + firstPlayer) % 2;       /* 0    = X, 1 = O */
  69.     HiliteBlob (GetBlobHandle (tttDonors, i), inFullBlob, normalDraw);
  70.     HiliteBlob (GetBlobHandle (tttDonors, 1 - i), inFullBlob, dimDraw);
  71.     if (i)
  72.         StatusMesg ("\pO's Move");
  73.     else
  74.         StatusMesg ("\pX's Move");
  75.     /*
  76.      * Freeze board except for positions occupied by current player and
  77.      * empty positions.
  78.      * This allows pieces to be played either by playing the piece at
  79.      * the top, or by duplicating them on the board.  (Can't drag onto
  80.      * another of own pieces, since replace transactions are disallowed.)
  81.      */
  82.     ThawBlobSet (tttReceptors);
  83.     for (b = FirstBlob (tttReceptors); b != nil; b = NextBlob (b))
  84.     {
  85.         if (BGlob (b) != nil && BGlob (b) != GetBlobHandle (tttDonors, i))
  86.             FreezeBlob (b);
  87.     }
  88. }
  89.  
  90.  
  91. static void
  92. Restart (void)
  93. {
  94.     HiliteControl (restartCtl, dimHilite);
  95.     ZUnglueGlobSet (tttReceptors);
  96.     HiliteBlobSet (tttReceptors, inFullBlob, normalDraw);
  97.     moves =    0;
  98.     SelectPlayer    ();
  99.     wait = false;
  100. }
  101.  
  102.  
  103. /*
  104.  * Dim the board positions that are not part of the win.  Dim them all
  105.  * on "cat's game."
  106.  */
  107.  
  108. static void
  109. ShowWinner (short pos)
  110. {
  111. short    i;
  112. BlobHandle    b;
  113.  
  114.     for (i = 0; i < 9; ++i)
  115.     {
  116.         b = GetBlobHandle (tttReceptors, i);
  117.         if ((pos % 2) == 0)             /* this pos not part of win */
  118.             HiliteBlob (b, inFullBlob, dimDraw);    /* so dim it */
  119.         pos >>= 1;
  120.     }
  121. }
  122.  
  123. static void
  124. TestConfig (short pos, short testPos)
  125. {
  126. short    i;
  127. BlobHandle    b;
  128.  
  129.     if ((pos & testPos) == testPos) /*    have a win */
  130.     {
  131.         haveWin    = true;
  132.         ShowWinner (testPos);
  133.     }
  134. }
  135.  
  136.  
  137. static void
  138. TestWin (BlobHandle b, short boardPos)
  139. {
  140.     if (!haveWin)     /*    don't bother if    other player already won */
  141.     {
  142.         TestConfig (boardPos, 0x007); /* top row */
  143.         TestConfig (boardPos, 0x038); /* middle row */
  144.         TestConfig (boardPos, 0x1c0); /* bottom row */
  145.         TestConfig (boardPos, 0x049); /* left column */
  146.         TestConfig (boardPos, 0x092); /* middle column */
  147.         TestConfig (boardPos, 0x124); /* right column */
  148.         TestConfig (boardPos, 0x111); /* diagonal */
  149.         TestConfig (boardPos, 0x054); /* diagonal */
  150.         if (haveWin)
  151.         {
  152.             if (b == xBlob)
  153.             {
  154.                 GameOver ("\pX Wins"); /* loser goes    first next time    */
  155.                 firstPlayer = 1;
  156.             }
  157.             else
  158.             {
  159.                 GameOver ("\pO Wins");
  160.                 firstPlayer = 0;
  161.             }
  162.         }
  163.     }
  164. }
  165.  
  166.  
  167. static short
  168. BoardPos (BlobHandle b)
  169. {
  170. short    i, mask, result;
  171. BlobHandle    b2;
  172.  
  173.     result = 0;
  174.     mask = 1;
  175.     for (i = 0; i < 9; ++i)
  176.     {
  177.         b2 = GetBlobHandle (tttReceptors, i);
  178.         if ((**b2).glob == b)         /* board occupied by desired piece    */
  179.             result |= mask;
  180.         mask <<= 1;
  181.     }
  182.     return (result);
  183. }
  184.  
  185.  
  186. static void
  187. CheckStatus (void)
  188. {
  189. short    xbPos, obPos;
  190.  
  191.     haveWin = false;
  192.     xbPos = BoardPos (xBlob);
  193.     obPos = BoardPos (oBlob);
  194.     TestWin (xBlob, xbPos);
  195.     TestWin (oBlob, obPos);
  196.     if (!haveWin)             /* no win, but board might be full now */
  197.     {
  198.         if ((xbPos | obPos) == 0x1ff)
  199.         {
  200.             ShowWinner (0);
  201.             GameOver ("\pCat's Game");
  202.             firstPlayer = 1 - firstPlayer; /* alternate on a draw */
  203.         }
  204.     }
  205. }
  206.  
  207.  
  208. static pascal void
  209. Mouse (Point pt, long t, short mods)
  210. {
  211. short            result;
  212. ControlHandle    ctl;
  213.  
  214.     if (FindControl    (pt, wind, &ctl))
  215.     {
  216.         if (TrackControl (ctl, pt, nil))
  217.         {
  218.             Restart ();
  219.         }
  220.     }
  221.     else if    (!wait)
  222.     {
  223.         BlobClick (pt, t, tttDonors, tttReceptors);
  224.         result = BClickResult ();
  225.         if (result == bcGlue || result == bcDup)
  226.         {
  227.             ++moves;
  228.             CheckStatus ();
  229.             if (!wait)     /*    no win yet */
  230.                 SelectPlayer ();
  231.         }
  232.     }
  233. }
  234.  
  235.  
  236. static pascal void
  237. Update (Boolean resized)
  238. {
  239.     DrawControls (wind);
  240.     StatusMesg (statusStr);
  241.     DrawGrid (3, 3,    xOffBoard, yOffBoard, bSqSize, bSqSize,    barWidth, barWidth);
  242.     DrawBlobSet (tttDonors);
  243.     DrawBlobSet (tttReceptors);
  244. }
  245.  
  246.  
  247. static pascal void
  248. Activate (Boolean active)
  249. {
  250.     if (active)
  251.     {
  252.         SetDragRects (wind);
  253.         SetBCPermissions (false, false, true, false, false);
  254.     }
  255. }
  256.  
  257.  
  258. static pascal void
  259. DrawRBlob (BlobHandle bDst, BlobHandle bSrc, short partCode)
  260. {
  261. Rect    r;
  262.  
  263.     if (partCode == inStatBlob)
  264.     {
  265.         r = BStatBox (bDst);
  266.         EraseRect (&r);
  267.     }
  268.     else
  269.     {
  270.         r = BDragBox (bDst);
  271.         EraseRect (&r);
  272.         FrameRect (&r);
  273.         InsetRect (&r, 2, 2);
  274.         FrameRect (&r);
  275.     }
  276. }
  277.  
  278.  
  279. static pascal void
  280. DrawDBlob (BlobHandle bDst, BlobHandle bSrc, short partCode)
  281. {
  282. Rect    r;
  283.  
  284.     r = BDragBox (bDst);
  285.     EraseRect (&r);
  286.     PenSize    (2, 2);
  287.     FrameRect (&r);
  288.     PenSize    (1, 1);
  289.     MoveTo (r.left+pSqSize/2-4, r.bottom-pSqSize/2+5);
  290.     DrawChar ((char) GetBRefCon (bSrc));
  291. }
  292.  
  293.  
  294. /*
  295.  * Make receptor blobs
  296.  */
  297.     
  298. static void
  299. MakeRBlob (Rect *r)
  300. {
  301. BlobHandle    b;
  302. Rect        r2;
  303.  
  304.     b = NewBlob (tttReceptors, true, 0, false, 0L);
  305.     r2 = *r;
  306.     InsetRect (&r2, 1, 1);
  307.     SetProcRectBlob (b, DrawRBlob, &r2, r);
  308. }
  309.  
  310.  
  311. static void
  312. MakeReceptors (void)
  313. {
  314.     tttReceptors = NewBlobSet ();
  315.     MakeBlobGrid (3, 3, xOffBoard, yOffBoard, bSqSize, bSqSize,
  316.                     barWidth, barWidth, &MakeRBlob);
  317. }
  318.  
  319.  
  320. /*
  321.  * Make donor blobs
  322.  */
  323.  
  324. static void
  325. MakeDBlob (BlobHandle *b, short ch, short x, short y)
  326. {
  327. Rect    r;
  328.  
  329.     *b = NewBlob (tttDonors, true, 9, false, 0L);
  330.     SetRect (&r, 0, 0, pSqSize, pSqSize);
  331.     OffsetRect (&r, x, y);
  332.     SetProcRectBlob (*b, DrawDBlob, &r, &r);
  333.     SetBRefCon (*b, ch);
  334. }
  335.  
  336.  
  337. static void
  338. MakeDonors (void)
  339. {
  340.     tttDonors = NewBlobSet ();
  341.     MakeDBlob (&xBlob, 'X', xMid-pSqSize-5, yOffPiece);
  342.     MakeDBlob (&oBlob, 'O', xMid+5, yOffPiece);
  343. }
  344.  
  345.  
  346. void
  347. TttInit (void)
  348. {
  349. Rect    r;
  350.  
  351.     SkelWindow (wind = GetDemoWind (tttWindRes),
  352.                 Mouse,            /* mouse clicks */
  353.                 nil,            /* key clicks */
  354.                 Update,            /* updates */
  355.                 Activate,        /* activate/deactivate events */
  356.                 nil,            /* close window */
  357.                 DoWClobber,        /* dispose of window */
  358.                 nil,            /* idle proc */
  359.                 false);            /* irrelevant, since no idle proc */
  360.  
  361.     MakeReceptors ();
  362.     MakeDonors ();
  363.     SetRect (&r, xMid-45, yOffBut, xMid+45, yOffBut+20);
  364.     restartCtl = NewControl (wind, &r, "\pRestart", true, 0, 0, 0,
  365.                                 pushButProc, 0L);
  366.     Restart ();
  367.     MakeFrontWind (wind);
  368. }
  369.